from typing import Union

from fastapi import FastAPI, Request
from pydantic import BaseModel

app = FastAPI()


# 查询参数必需
@app.get("/parameter/")
async def parameter(name: str, age: int):
    return {"name": name, "age": age}


# 查询参数默认值
@app.get("/default/")
async def default(name: str, age: int = 25):
    return {"name": name, "age": age}


# 查询参数可选值
@app.get("/Optional")
async def Optional(q: Union[str, None] = None):
    if q:
        return {"q": q}
    else:
        return {"q": "No query parameter"}


# 查询参数类型转换
@app.get("/conversion/")
async def read_item(short: bool = False):
    return {"short": short}


# 查询参数多个
@app.get("/multiple/{user_id}/list/{item_id}")
async def read_item(user_id: int, item_id: str, q: Union[str, None] = None, username: str = None):
    item = {"user_id": user_id, "item_id": item_id}
    if q:
        item.update({"q": q})
    if username:
        item.update({"username": username})
    return item


# 请求体，使用Request对象解析content-type为application/json的请求体
@app.post("/body/")
async def body_request(request: Request):
    data = await request.json()  # await 等待请求体解析完成
    print(data.get("name"))
    return data


# 请求体，使用Request对象解析content-type为application/x-www-form-urlencoded的请求体
@app.post("/form/")
async def form_request(request: Request):
    data = await request.body()  # await 等待请求体解析完成
    print(data)
    return data


# 请求体，使用Request对象解析content-type为multipart/form-data的请求体
@app.post("/file/")
async def file_request(request: Request):
    data = await request.form()  # await 等待请求体解析完成
    print(data)
    return data


# 请求头
@app.get("/header/")
async def header(request: Request):
    return request.headers.get("User-Agent")


# 其他请求
@app.get("/other/")
async def other(request: Request):
    url = request.url  # 请求URL
    method = request.method  # 请求方法
    cokies = request.cookies  # 请求Cookies
    client = request.client  # 客户端IP地址
    return {"url": str(url), "method": method, "cookies": cokies, "client": str(client)}


# 创建一个继承自 BaseModel 的类，定义请求体结构。属性类型使用Python标准类型注解，并可设置默认值以标记其为可选。
class Item(BaseModel):
    name: str
    description: str | None = None  # 可选字段，默认为None
    price: float
    tax: float | None = None  # 可选字段，默认为None


# 请求体，使用Pydantic模型解析请求体
@app.post("/model/")
async def model_request(item: Item):
    return item


# 首先，定义两个Pydantic模型：一个用于表示单个用户及其项目列表(UserWithProjects)，另一个用于包含用户列表的顶层数据结构(UsersData):
class Project(BaseModel):
    project_id: int
    name: str


class User(BaseModel):
    id: int
    name: str
    projects: list[Project]


class UsersData(BaseModel):
    users: list[User]


# 接下来，创建一个路径操作函数来接收并处理这个嵌套的JSON数据。你可以通过将UsersData作为函数参数来自动解析传入的JSON数据：
@app.post("/users/")
async def receive_users_data(users_data: UsersData):
    # 现在你可以直接使用users_data.users来访问用户列表及其项目
    for user in users_data.users:
        print(f"User ID: {user.id}, Name: {user.name}")
        for project in user.projects:
            print(f"  Project ID: {project.project_id}, Name: {project.name}")

    return {"message": "Users data received successfully."}


if __name__ == "__main__":
    import uvicorn

    """
    app: 是Fast API应用程序。
    host: 是服务器的主机名。
    port: 是服务器监听的端口。
    reload: 设置为True时，服务器将自动重新加载代码。
    """
    uvicorn.run(app, host="127.0.0.1", port=8000, reload=True)
